#include "SemanticNodeClass.h"

#include "main2.h"
#include "../errors_warnings.h"

SemanticNodeClass::SemanticNodeClass(const SyntaxTreeNode& syntaxNode, SemanticNode* parent) :	SemanticNode(parent) {

	if (syntaxNode.Production != Gr_ClassDefinition__ClassMods_TemplateDefinition_class_NAME_ClassInherit_spLCBrac_UsingDirectives_ClassBodyAdd_spRCBrac) {

		// se ovo ikad moze desit?
		// mislim da samo ako smo nest krivo napravili

	}

	// obradjivanje modifikatora
	this->mod = 0x00;
	bool abstractOrSealed = false, privPublicProt = false;
	for (int i = 0; i < syntaxNode.Nodes->GetData(0)->Nodes->GetCount(); ++i) {
		switch (syntaxNode.Nodes->GetData(0)->Nodes->GetData(i)->Production){
		case Gr_ClassMod__abstract:
			if (abstractOrSealed){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(syntaxNode.Nodes->GetData(0)->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
				break;
			}
			abstractOrSealed = true;
			mod |= CM_Abstract;
			break;
		case Gr_ClassMod__final:
			if (abstractOrSealed){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(syntaxNode.Nodes->GetData(0)->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_ILLEGAL_MODIFIERS_COMBINATION);
				break;
			}
			abstractOrSealed = true;
			mod |= CM_Sealed;
			break;
		case Gr_ClassMod__private:
			if (privPublicProt){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(syntaxNode.Nodes->GetData(0)->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
				break;
			}
			privPublicProt = true;
			mod |= CM_Private;
			break;
		case Gr_ClassMod__protected:
			if (privPublicProt){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(syntaxNode.Nodes->GetData(0)->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
				break;
			}
			privPublicProt = true;
			mod |= CM_Protected;
			break;
		case Gr_ClassMod__public:
			if (privPublicProt){
				LexicUnit lu = CompilerData->Units->GetLexicUnit(syntaxNode.Nodes->GetData(0)->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
				break;
			}
			privPublicProt = true;
			mod |= CM_Public;
			break;
		default:;
		}
	}
	if (!privPublicProt) mod |= CM_Private;

	// obradjivanje templatea
	if (syntaxNode.Nodes->GetData(1)->Production == Gr_TemplateDefinition__template_TemplateUse) {
		this->templateNames = flattenTemplateIdentifiers(*syntaxNode.Nodes->GetData(1)->Nodes->GetData(1)->Nodes->GetData(1));
	}

	// izvadi ime
	name = CompilerData->Units->GetLexicUnitString(&CompilerData->Units->GetLexicUnit(syntaxNode.Nodes->GetData(3)->LexUnitID));

	// obradit nasljedjivanje
	if (syntaxNode.Nodes->GetData(4)->Production == Gr_ClassInherit__spColon_ClassInheritName) {
		ciInherited.name = flattenNamePeriodAdd(*syntaxNode.Nodes->GetData(4)->Nodes->GetData(1)->Nodes->GetData(0));
		if (syntaxNode.Nodes->GetData(4)->Nodes->GetData(1)->Production == Gr_ClassInheritName__Name_TemplateUse) {
			ciInherited.templates = flattenTemplateIdentifiers(*syntaxNode.Nodes->GetData(4)->Nodes->GetData(1)->Nodes->GetData(1)->Nodes->GetData(1));
		}
		inherited = true;
	} else if (syntaxNode.Nodes->GetData(4)->Production == Gr_ClassInherit__epsilon) inherited = false;
	else {
		// ovo se ne bi smjelo dogoditi
	}

	// obradit using
	usingDirectives = new UsingDirectives(syntaxNode.Nodes->GetData(3), this);

}

SemanticNodeClass::~SemanticNodeClass() {
	//delete classBody;
}
/**
 *  @fn	void SemanticNodeClass::addClass(SemanticNodeClass *classNode)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/6/2009.
 *
 *  @param	classNode	.
 */
void SemanticNodeClass::addClass(SemanticNodeClass *classNode) {
	classes.push_back(classNode);
}
/**
 *  @fn	void SemanticNodeClass::addEnum(SemanticNodeEnum *enumNode)
 *
 *  @brief	Adds an enum.
 *
 *  @author	Nikola Novak
 *  @date	9/14/2009
 *
 *  @param	enumNode	If non-null, the enum node.
 */
void SemanticNodeClass::addEnum(SemanticNodeEnum *enumNode) {
	enums.push_back(enumNode);
}
/**
 *  @fn	void SemanticNodeClass::addFields(std::vector<SemanticNodeField*> fieldsNode)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/6/2009.
 *
 *  @param	fieldsNode	.
 */
void SemanticNodeClass::addFields(std::vector<SemanticNodeField*> fieldNodes) {
	for (std::vector<SemanticNodeField *>::iterator i = fieldNodes.begin(); i != fieldNodes.end(); ++i) {
		fields.push_back(*i);
	}
}
/**
 *  @fn	void SemanticNodeClass::addProperty(SemanticNodeProperty *propertyNode)
 *
 *  @brief	Adds a property.
 *
 *  @author	Nikola Novak
 *  @date	9/20/2009
 *
 *  @param	propertyNode	If non-null, the property node.
 */
void SemanticNodeClass::addProperty(SemanticNodeProperty *propertyNode) {
	properties.push_back(propertyNode);
}
/**
 *  @fn	void SemanticNodeClass::addMethod(SemanticNodeMethod *methodNode)
 *
 *  @brief	Adds a method.
 *
 *  @author	Nikola Novak
 *  @date	9/20/2009
 *
 *  @param	methodNode	If non-null, the method node.
 */
void SemanticNodeClass::addMethod(SemanticNodeMethod *methodNode) {
	// ToDo: provjeriti Signature metoda
	methods.push_back(methodNode);
}
/**
 *  @fn	void SemanticNodeClass::addConstructor(SemanticNodeMethod *constructorNode)
 *
 *  @brief	Adds a constructor.
 *
 *  @author	Nikola Novak
 *  @date	9/20/2009
 *
 *  @param	constructorNode	If non-null, the constructor node.
 */
void SemanticNodeClass::addConstructor(SemanticNodeConstructor *constructorNode) {
	// ToDo: provjeriti Signature konstruktora
	// Oprez: ne provjerava se je li ime konstruktora jednako imenu klase u kojoj se nalazi
	//        to je potrebno provjeriti u kasnijim fazama
	constructors.push_back(constructorNode);
}
/**
 *  @fn	int SemanticNodeClass::nameCount(std::string name)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/6/2009.
 *
 *  @param	name	.
 *
 *  @return	.
 */
int SemanticNodeClass::nameCount(std::string name) {
	int cnt = 0;
	//cnt += classes.count(name);
	//cnt += fields.count(name);
	//cnt += enums.count(name);
	//cnt += constructors.count(name);
	//cnt += methods.count(name);
	return cnt;
}

std::string SemanticNodeClass::toDebugString(int tab) {
	std::ostringstream ss;
	for (int i = 0; i < tab; i++) ss << DEBUG_STRING_RAZMAK;
	if (mod & CM_Private) ss << "private ";
	if (mod & CM_Protected) ss << "protected ";
	if (mod & CM_Public) ss << "public ";
	if (mod & CM_Abstract) ss << "abstract ";
	if (mod & CM_Sealed) ss << "final ";
	// template
	ss << "template<" << writeTemplate(templateNames) << "> class " << name << " ";
	// inheritance
	if (inherited) ss << ": " << ciInherited.name << "<" << writeTemplate(ciInherited.templates) << "> ";

	// usings
	ss << usingDirectives->toDebugString(tab + 1) << std::endl;

	// fields
	for (std::vector<SemanticNodeField *>::iterator i = fields.begin(); i != fields.end(); ++i) {
		ss << (*i)->toDebugString(tab + 1);
	}

	// ispis nodova u klasi
	for (std::vector<SemanticNodeClass *>::iterator i = classes.begin(); i != classes.end(); ++i) ss << (*i)->toDebugString(tab + 1);
	for (std::vector<SemanticNodeEnum *>::iterator i = enums.begin(); i != enums.end(); ++i) ss << (*i)->toDebugString(tab + 1);
	for (std::vector<SemanticNodeField *>::iterator i = fields.begin(); i != fields.end(); ++i) ss << (*i)->toDebugString(tab + 1);
	for (std::vector<SemanticNodeMethod *>::iterator i = methods.begin(); i != methods.end(); ++i) ss << (*i)->toDebugString(tab + 1);
	for (std::vector<SemanticNodeConstructor *>::iterator i = constructors.begin(); i != constructors.end(); ++i) ss << (*i)->toDebugString(tab + 1);
	for (std::vector<SemanticNodeProperty *>::iterator i = properties.begin(); i != properties.end(); ++i) ss << (*i)->toDebugString(tab + 1);

	//ss << classBody->toDebugString(tab + 1);
	return ss.str();
}
/**
 *  @fn	std::string SemanticNodeClass::getName(void)
 *
 *  @brief	Gets the name.
 *
 *  @author	Nikola Novak
 *  @date	6/1/2009
 *
 *  @return	The name.
 */
std::string SemanticNodeClass::getName(void) {
	return name;
}


// ispis izravnatog templatea
std::string SemanticNodeClass::writeTemplate(std::vector<std::string> &tpl) {
	std::ostringstream ss;
	for (std::vector<std::string>::iterator i = tpl.begin(); i != tpl.end();) {
		ss << i->data();
		if ((++i) != tpl.end())
			ss << ", ";
	}
	return ss.str();
}

